<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script typet="text/javascript" src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>
</head>

<script>
    (function (str) {
        var J = {};
        var style='.jalert,.jtip{position:fixed; left:0; top:0; visibility:hidden; opacity:0;transition:0.2s all;z-index:100;width:100vw;height: 100vh;user-select: none;background: rgba(0,0,0,0.1);}\
			.jalert-title{padding:0 10px; text-align: center;background:#fff;}\
			.jalert-title-text{color: #333; height:40px; line-height: 40px; font-size: 16px; overflow:hidden;text-overflow:ellipsis;}\
			.jalert-content,.jtip-content{width:360px; min-height:100px;background: #FFFFFF;box-shadow: 0px 0 30px 0 rgba(0, 0, 0, 0.3); position: absolute; left: 0; top: 0; z-index: 2;border-radius:15px; overflow: hidden;margin-top:20px; transition:0.2s margin;transform: translateZ(0);}\
			.jalert-bottom{padding:0 20px 20px 20px; text-align: center;overflow: hidden}\
			.jalert-bottom .btn{min-width:100px; cursor:pointer; height:35px; line-height: 34px; border-radius: 20px; text-align: center;box-sizing:border-box; color:#333;background:#ff5400;border:solid 1px #ff5400; outline:none; transition:0.2s opacity;user-select:none;}\
			.jalert-bottom .btn:first-child{ color:#fff;}\
			.jalert-bottom .btn:last-child{ background:#fff;border:solid 1px #ccc;margin-left:20px;}\
			.jalert-bottom .btn:hover{opacity:0.8;}\
			.jalert-content .content{padding:15px 25px 25px 25px;overflow: auto;text-align: center;}\
			.jalert-content .div{word-break: break-all; display: inline-block;text-align: left;color:#999;font-size: 16px;}\
			.jalert.on,.jtip.on{visibility: visible; opacity: 1;}\
			.jalert.on .jalert-content,.jalert.on .jtip-content{margin-top:0;}\
			.jalert-content.mobile .btn{min-width:25vw;}\
			.jalert-content.mobile .btn:last-child{margin-left:5vw;}\
			.jalert-content.mobile .jalert-title{padding:0 5vw;}\
			.jalert-content.mobile .jalert-title-text{height:12vw; line-height: 12vw; font-size: 16px;}\
			.jalert-content.mobile .content{padding:3vw 5vw 5vw 5vw;}\
            .jtip{text-align:center;background:rgba(255,255,255,0.5);line-height:100vh;}\
            .jtip-content{width:auto; min-height:auto;background:rgba(0,0,0,0.7);line-height:1.3rem;color:#fff;padding:0.5rem 0.8rem;border-radius:0.5rem;position:static;display:inline-block;word-break: break-all;text-align:left;}\
			.jgray{-webkit-filter: grayscale(100%);-moz-filter: grayscale(100%);-ms-filter: grayscale(100%);-o-filter: grayscale(100%);filter: grayscale(100%);filter: gray;opacity:0.5}';
        var styleEle=document.createElement('style');
        styleEle.innerHTML=style;
        document.querySelector('head').appendChild(styleEle);

		var verify_rules = {
			len: function (v, v2) {return v.length == v2;},//字符串长度
			minLen: function (v, v2) {return v.length >= v2;},//最小长度
			maxLen: function (v, v2) {return v.length <= v2;},//最大长度
			notEmpty: function (v) {return v?(v.toString().replace(/\s+/g, '') ? true : false):false;},//为空判断
			min: function (v, v2) {return Number(v) >= Number(v2);},//最小值
			max: function (v, v2) {return Number(v) <= Number(v2);},//最大值
			idCard: function (v) {return (/^\d{17}[\d|x|X]$|^\d{15}$/).test(v);},//身份证
			mobile: function (v) {return (/^0?(13|14|15|16|17|18|19)[0-9]{9}$/).test(v);},//手机号码
			int: function (v) {return (/^-?\\d+$/).test(v);},//整数
			number: function (v) {return (/^(-?\d+)(\.\d+)?$/).test(v);},//浮点数
			email: function (v) {return (/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/).test(v);},//电子邮件
			qq: function (v) {return (/[0-9]{5,11}/).test(v);},//QQ号
			url: function (v) {return (/^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/).test(v);},//网址
			chinese: function (v) {return (/^[\u4e00-\u9fa5]{0,}$/).test(v);},//纯中文字符串
			zhen: function (v) {return (/^[A-Za-z0-9]+$/).test(v);},//中英文字符串
			zh_en: function (v) {return (/^\w+$/).test(v);},//中英文下划线
			en: function (v) {return (/^[A-Za-z]+$/).test(v);},//英文字符串
		}

		var verify_msg = {
			notEmpty: '不能为空',
			minLen: "长度不足{s}",
			maxLen: "长度超过{s}",
			len: "长度不相等",
			min: "不能小于{s}", 
			max: "不能大于{s}",
			idCard: '身份证格式不正确',
			mobile: '手机号码格式不正确',
			int: '不是整数',
			number: '不是数字',
			email: '邮箱格式不正确',
			qq: '不是QQ号',
			url: '网址格式不正确',
			chinese: '只能是汉字',
			zhen: '只能是数字和英文字母组成',
			zh_en: '只能由数字、26个英文字母或者下划线组成',
			en: '只能是英文字符串',
		}
		//dom筛选
		J.dom=function(selector,parent){
			parent=parent?parent:document;
		    var doms=parent.querySelectorAll(selector);
		    var res=doms.length==1?doms[0]:doms,tmp;
		    res.forEach=function(callback){
		        for(var i=0;i<doms.length;i++){
					if(callback.call(doms[i],doms[i],i)==false){
						break;
					}
		        }
		    }            
		    return res;
		}
		 
		 //去空格
		 String.prototype.trim = function(mode){
		     mode=mode?mode:'all'
		     var rex={
		         'all':/\s*/g,
		         'lr':/(^\s*)|(\s*$)/g,
		         'l':/(^\s*)/g,
		         'r':/(\s*$)/g,
		     }
		     return this.replace(rex[mode], "");  
		 }  
		 
		 Date.prototype.format = function (fmt) {
		     //"yyyy-MM-dd hh:mm:ss.S"
		     var o = {
		         "M+": this.getMonth() + 1, //月份
		         "d+": this.getDate(), //日
		         "h+": this.getHours(), //小时
		         "m+": this.getMinutes(), //分
		         "s+": this.getSeconds(), //秒
		         "q+": Math.floor((this.getMonth() + 3) / 3), //季度
		         "S": this.getMilliseconds() //毫秒
		     };
		     if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
		     for (var k in o){
		         if (new RegExp("(" + k + ")").test(fmt)){
                     fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
                 }
             }
		     return fmt;
		 }
		 
		 Array.prototype.removeToIndex = function (index) {
		     this.splice(index, 1);
		 }
		 
		 Array.prototype.getIndex = function (value) {
		     var index=[]
		     this.forEach(function (v, k) {
		         if (v == value) {
		             index.push(k)                       
		         }
		     })
		 	return input;
		 }
		 
		 Array.prototype.removeToValue = function () {
		     var self=this;
		     var arr=[].slice.call(arguments),index=[];
		     this.forEach(function (v, k) {
		         arr.forEach(function(v2){
		             if (v2==v)index.push(k);              
		         })  
		     });
		     index.sort(function(a,b){
		         return b-a;
		     });
		     index.forEach(function(v){
		         self.splice(v,1);
		     });
		 }
		    
		 Element.prototype.addClass=function(str){
		     this.className=this.className.trim('lr')+" "+str;
		 }
		 
		 Element.prototype.removeClass=function(str){
		     var arr=this.className.split(' ');            
		     arr.removeToValue("",'c','b',str);            
		     this.className=arr.join(' ');
		 }
         Element.prototype.remove=function(){
		     this.parentNode.removeChild(this);
		 }
		 
		 Element.prototype.find=function(selector){
		    return J.dom(selector,this);
		 }
		 
		/**
         * xmlHttpRequest异步请求
         * options={
         *   url:请求地址
         *   type:请求方式 get(默认)/post
         *   data:请求参数 string/object
         *   header:object 设置request头部信息
         *   success:成功回调 function(data,res) this对象为xhr
         *   error:成功回调 function(data,res) this对象为xhr
		 * 	 async:是否异步 bool true(默认异步)/false(同步)
         * }
         * */
        J.ajax = function (options) {
            if (!options.url) return;
            var xhr = new XMLHttpRequest();
            var type = options.type ? options.type.toUpperCase() : "GET";
            var data=options.data;
			var async=options.async==false?false:true;
            if(data)data=J.queryFormat(data);
            if(!options.header)options.header={};
            if(!options.header['Content-Type'])options.header['Content-Type']='application/x-www-form-urlencoded; charset=UTF-8';
            if(type=='GET' && data){
                options.url+=(options.url.indexOf('?')>-1?'&':"?")+data;
            }
            xhr.open(type, options.url,async);
            xhr.withCredentials = options.withCredentials ? false : true;
            try {
                for (var i in options.header) {
                    xhr.setRequestHeader(i, options.header[i]);
                }
            } catch (e) { }
            xhr.onload = function (res) {
                var data2 = res.target.response;
                try { data2 = JSON.parse(data2); } catch (e) { }
                this.headers = parseHeaders(this.getAllResponseHeaders())
                if (options.success) options.success.call(this, data2, res);
            }
            xhr.onerror = function (res) {
                var data2 = res.target.response;
                try { data2 = JSON.parse(data2); } catch (e) { }
                this.headers = parseHeaders(this.getAllResponseHeaders())
                if (options.error) options.error.call(this, data2, res);
            }
            xhr.send(type == "POST" ? data : "");
            
            function parseHeaders(str) {
                var tmp = {}, tmp2;
                str = str.split('\n');
                for (var i = 0; i < str.length; i++) {
                    tmp2 = str[i].split(': ')
                    if (tmp2[0]) tmp[tmp2[0]] = tmp2[1];
                }
                return tmp;
            }
        }
        //格式化请求参数
        J.queryFormat=function(query,notEncode){
            if(['string','formdata'].indexOf(J.typeof(query))>-1)return query;
            var tmp=[];
            function parse(obj,k){
                if(!k)return;
                var i;
                if(J.typeof(obj)=='array'){
                    obj.forEach(function(v,k2){               
                        parse(v,k+"["+((k2==0 || (J.typeof(v)!='array' && J.typeof(v)!='object'))?'':k2)+"]");
                    })                
                }else if(J.typeof(obj)=='object'){
                    for(i in obj)parse(obj[i],k+"["+i+"]");
                }else{
                    if(k)tmp.push(k+"="+obj.toString());
                }
            }
            for(var a in query)parse(query[a],a);
            return notEncode?tmp.join('&'):encodeURI(tmp.join('&'));
        }

        J.query =(function () {
            var arr = location.search.substr(1).split('&'), res = {}, tmp;
            for (var i = 0; i < arr.length; i++) {
                tmp = arr[i].split('=');
                if (tmp[0]) res[tmp[0]] = decodeURI(tmp[1]);
            }
            return res;
        }());

        J.objlen = function (obj) {
            var i = 0, a;
            for (a in obj) i++
            return i;
        }
        //判断变量类型
        J.typeof = function (obj) {
            return Object.prototype.toString.call(obj).replace(/\[object |]/g, '').toLowerCase();
        }
        //判断平台
        J.platform=(function(){
            var userAgentInfo = navigator.userAgent;
            var Agents = ["Android", "iPhone","SymbianOS", "Windows Phone","iPad", "iPod"];
            var flag;
            for (var v = 0; v < Agents.length; v++) {
                if (userAgentInfo.indexOf(Agents[v]) > -1) {
                    flag = Agents[v];
                    break;
                }
            }
            return flag?flag:'pc';
        }());
        //判断浏览器
        J.browser=(function(){
            if(!!window.ActiveXObject || "ActiveXObject" in window){
                return "IE";
            }
            if(navigator.userAgent.indexOf("Firefox")!=-1){
                return "Firefox";
            }
            if(navigator.userAgent.indexOf("Chrome")!=-1){
                return "Chrome";
            }
            if(navigator.userAgent.indexOf("Safari")!=-1){
                return "Safari";
            }
        }());
        //转义html标签
        J.htmlEncode=function (text) {
            return text.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g,'<').replace(/>/g, '>');
        }
        //还原html标签
        J.htmlDecode=function(text) {
            return text.replace(/&/g, '&').replace(/"/g, '\"').replace(/</g, '<').replace(/>/g, '>');
        }
        //防止短时间连续点击
        J.antiContinuityClick=function(func,wait){
			wait=wait?wait:1000
            var previous = 0;
            return function() {
                var now = Date.now();
                if (now - previous > wait) {
                    func.apply(this, arguments);
                    previous = now;
                }
            }
        }
        //防止重复点击
        J.antiRepeatClick=function(func,text){           
            return function() {
                var o=event.currentTarget || event.srcElement;       
                if(!o.reset){
                    o._text=o.innerHTML;
                    o.reset=function(){
                        o.removeClass("jgray");                      
                        o._disabled=false;
                        if(text)o.innerHTML=o._text;
                    }
                }
                if(!o._disabled){
                    o._disabled=true;
                    o.addClass("jgray");
                    if(text)o.innerHTML=text;
                    func.apply(this, arguments);
                }                
            }
        }
        //弹框
        J.alert=(function(){
            /*对话框*/
            var div=document.createElement('div');
            var tmphtml='<div class="jalert-content"><div class="jalert-title"><div class="jalert-title-text"></div></div><div class="content"><div class="div" style="max-height:60vh;overflow:auto"></div></div><div class="jalert-bottom"><button class="btn">确定</button><button class="btn">取消</button></div></div>';
           
            div.innerHTML=tmphtml;
            div.className="jalert";
            div.id='jAlert';
            J.dom('html').appendChild(div);
            var tip=J.dom('#jAlert');          
            var btn=tip.find('.jalert-bottom .btn');
            var jContent=tip.find('.jalert-content');
            J.platform!='pc' && jContent.addClass('mobile');
            return function(content,options){
                /**
                 * content:对话框内容
                 * options:{
                 *     width:对话框宽度,
                 *     title:标题,
                 *     confirmText:确定按钮文字，默认为确定,
                 *     success:function 点击确定的回调函数,
                 *     cancel:function 点击取消的回调函数,
                 *     isShowCancel:bool 是否显示取消按钮
                 * }
                 */
                if(!content)return;
                if(!options)options={};
                var top,left;
                options.title=options.title?options.title:'温馨提示';
                options.width=options.width?options.width+'px':'360px';
                options.confirmText=options.confirmText?options.confirmText:'确定';
                options.cancelText=options.cancelText?options.cancelText:'取消';
                options.isShowCancel=options.isShowCancel!=false?true:false;
                tip.find('.jalert-title-text').innerHTML=options.title;
                tip.find('.content .div').innerHTML=content;
                btn[0].innerHTML=options.confirmText;
                btn[1].innerHTML=options.cancelText;
                jContent.style.width=J.platform=='pc'?options.width:'80vw';
                top=(document.documentElement.clientHeight-jContent.offsetHeight)/2;
                left=(document.documentElement.clientWidth-jContent.offsetWidth)/2;
                if(top-40<0)top=0;
                if(left<0)left=0;
                jContent.style.top=top-40+'px';
                jContent.style.left=left+'px';
                tip.addClass("on");
                btn[1].style.display=options.isShowCancel?'inline-block':'none';
                btn[0].onclick=function(){
                    options.success && options.success();
                    tip.removeClass("on");
                }
                btn[1].onclick=function(){
                    options.cancel && options.cancel();
                    tip.removeClass("on");
                }
            }
			
        }());
		//提示框
        J.tip=(function(){
            var div=document.createElement('div'),fors;
            var w=J.platform=='pc'?'300px':'80vw';
            div.innerHTML='<div class="jtip-content" style="max-width:'+w+';"></div>';
            div.className="jtip";
            J.dom('html').appendChild(div);
            return function(str,t){
                clearTimeout(fors)
                div.find('.jtip-content').innerHTML=str;
                div.addClass('on');
                fors=setTimeout(function(){
                    div.removeClass('on');
                },(t || 2000))
            }
        }());
        /*
			表单验证
			dom:表单元素父级 值为css选择器表达式
			表单元素例 :<input type="text" verify-mothod="notEmpty,min|20" verify-error="空了,小了">
			verify-error 错误提示文字,有多个验证方法用,..
			verify-mothod 验证方法|比较值,验证方法|比较值,...
		*/     
		J.verify=function(dom,callback){
			var ele='input[verify-mothod],textarea[verify-mothod],select[verify-mothod]';
			var error=[];
			
			function verify(mothod,v,v2,text){
				var res,msg=text?text:(verify_msg[mothod]?verify_msg[mothod]:'验证未通过');
				if(verify_rules[mothod]){
					res=verify_rules[mothod](v,v2) 
				}else if(window[mothod]){
					res=window[mothod].call(this,v,v2)
				}else{
					res=false;
					msg=mothod+'方法不存在';
				}
				if(!res){
					error.push({target:this,msg:msg.replace('{s}',v2?v2:"")});
				}
				return res;
			}

            function tipError(err){
                J.alert(err[0].msg);
                return false;
            }

            function start(){
                callback=callback || tipError;
                J.dom(dom).forEach(function(){
                    this.find(ele).forEach(function(){
                        var m=this.getAttribute('verify-mothod').split(',');
                        var v=this.value;
                        var text=this.getAttribute('verify-error');
                        text=text?text.split(','):[];
                        for(var i=0;i<m.length;i++){
                            var tmp=m[i].split('|')
                            if(tmp[0]){
                                if(!verify.call(this,tmp[0],v,tmp[1],text[i]))break;
                            }else{
                                error.push({target:this,msg:'验证方法不存在'});
                                break;
                            }
                        }
                    });
                });
                error.length==0 || callback(error);
                return error.length==0;
            }
			
			return {
				get verify(){
                    return start();
                }
			}
		}
        
        //简易模板解析
        J.template=function(htmlStr,separator){
            if(J.typeof(htmlStr)=='string'){
                separator=separator?separator:'{{,}}';
                separator=separator.split(',')
                htmlStr=htmlStr.replace(/'/g,"\\'");
                htmlStr=htmlStr.replace(/\n/g,"");
                htmlStr=htmlStr.replace(/&gt;/g,">");
                htmlStr=htmlStr.replace(/&lt;/g,"<");
                htmlStr=htmlStr.replace(/ +/g," ");
                var tmp='';
                var rexStr={
                    '{{if .*}}':[
                        ["{{if","';if("],
                        ["}}","){tmp+='"]
                    ],
                    '{{else}}':[
                        ["{{else}}","';}else{tmp+='"]
                    ],
                    '{{elseif .*}}':[
                        ["{{elseif","';}else if("],
                        ["}}","){tmp+='"]
                    ],
                    '{{/if}}':[
                        ["{{/if}}","';}tmp+='"]
                    ],
                    '{{for .*}}':[
                        ["{{for","';for("],
                        ["}}","){tmp+='"]
                    ],
                    '{{/for}}':[
                        ["{{/for}}","';}tmp+='"]
                    ],
                    '{{[^{}]*}}':[
                        ['{{',"'+("],
                        ['}}',")+'"]
                    ],
                   
                }
                for(var i in rexStr){
                    htmlStr=htmlStr.replace(new RegExp(i, 'g'),function(__str__){
                        var str=__str__;
                        for(var k=0;k<rexStr[i].length;k++){
                            str=str.replace(rexStr[i][k][0],rexStr[i][k][1]);
                        }
                        return str;
                    });
                }
                htmlStr="tmp+='"+htmlStr+"';"
                
            }
            eval(htmlStr);
            return tmp;
        }

        window[str] = J; 
    }('J'));
</script>

<body>
    <div  id="abc" class="abc">
        <button id="btn" style="background:#aaa;width:150px;height:40px;border:none;color:red;border-radius:15px;" class="b c b c b   fda" onclick="h(222);">点击试试</button>
    </div>
    <div class="abc">
		<input type="text" verify-mothod="notEmpty,min|20" verify-error="空了,小了">
		<input type="text" verify-mothod="abcd">
    </div>
    <div id="t">
       {{for i in b}}
           {{i}}---------{{b[i]}}444444\n
       {{/for}}
    </div>
</body>

</html>
<script>
    var h=J.antiRepeatClick(function(d){
        //console.log(d)
    },'正在加载...');
    var a=5,b={a:1,b:2,c:3};
    console.log(J.template(t.innerHTML));
    J.tip('正在加载')


</script>